package org.micode.libs.servlet.helper;

import lombok.extern.slf4j.Slf4j;
import org.micode.common.domain.base.BaseUserCache;
import org.micode.common.domain.vo.ConvertFileVO;
import org.micode.common.domain.vo.FileVO;
import org.micode.common.file.FileResponseVO;
import org.micode.common.file.FileUploadVO;
import org.micode.common.file.TargetPathHelper;
import org.micode.common.file.UploadFileTypeEnum;
import org.micode.common.utils.FileExtUtils;
import org.springframework.http.MediaType;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.function.Function;
import java.util.zip.GZIPOutputStream;

@Slf4j
public class ServletFileHelper {

    public static FileResponseVO uploadFile(MultipartFile filePart,
                                            Integer userType,
                                            UploadFileTypeEnum fileType,
                                            String bizType,
                                            String langType,
                                            BaseUserCache currentUser,
                                            TargetPathHelper targetPathHelper,
                                            Function<FileUploadVO, Integer> doSaveFileInfo,
                                            Function<ConvertFileVO, Integer> doConvertFile) throws IOException {
        String filename = filePart.getOriginalFilename();
        log.info("=======================Upload File=======================");
        log.info(filename);

        Long fileId = targetPathHelper.getFileId();
        String newFilename = targetPathHelper.getNewFilename();
        Path targetPath = targetPathHelper.getTargetPath();

        String newRealName = targetPathHelper.getNewRealName();
        String newRealPath = targetPathHelper.getNewRealPath();

        // 再建立新的
        Path tempFile = Files.createFile(targetPath);

        // 方法二
        filePart.transferTo(tempFile.toFile());

        log.info("File written...{}", newFilename);
        String filePath = targetPath.toString();
        doSaveFileInfo.apply(
                new FileUploadVO(fileId, userType, currentUser,
                        newRealPath, filename, newRealName, fileType.getCode(),
                        getRealFileSize(filePath),
                        bizType, langType, null));

        log.debug("Start converting file format...{}", newFilename);
        // 文件转换格式
        doConvertFile.apply(new ConvertFileVO(filePath, newRealPath));

        log.info(targetPath.toString());
        log.info("======================================================");

        FileResponseVO response = new FileResponseVO();
        response.setFileId(fileId);
        response.setFilename(newFilename);
        response.setFileUrl(targetPath.toString());

        return response;
    }

    private static Long getRealFileSize(String filePath) {
        return FileExtUtils.getFileSize(filePath);
    }

    public static void downloadFile(FileVO fileVO, HttpServletResponse response) {
        downloadFile(fileVO.getUrl(), fileVO.readMediaType(), response);
    }

    public static void downloadFile(String filePath,
                                    boolean zipTheFile,
                                    HttpServletResponse response) {
        downloadFile(filePath, "application/x-download", zipTheFile, response);
    }

    public static void downloadFile(String filePath, String fileMediaType,
                                    HttpServletResponse response) {
        downloadFile(filePath, fileMediaType, true, response);
    }

    public static void downloadFile(String filePath, String fileMediaType,
                                    boolean zipTheFile,
                                    HttpServletResponse response) {
        if (FileExtUtils.existFile(filePath)) {
            File f = new File(filePath);
            try {
                BufferedInputStream br = new BufferedInputStream(new FileInputStream(f));
                try {
                    byte[] buf = new byte[1024];
                    int len = 0;

                    String theFilename = URLEncoder.encode(f.getName(), "UTF-8");
                    response.reset(); // 非常重要
                    response.setContentType(fileMediaType);
//                    response.setHeader("Access-Control-Allow-Credentials", "true");
                    response.setHeader("Access-Control-Allow-Origin", "*");
                    response.setHeader("Content-Disposition", "attachment; filename=" + theFilename);
                    if (zipTheFile) {
                        response.setHeader("Content-Encoding", "gzip");
                    }
                    OutputStream out = response.getOutputStream();
                    try {
                        if (zipTheFile) {
                            GZIPOutputStream gzipOut = new GZIPOutputStream(out);
                            try {
                                while ((len = br.read(buf)) > 0) {
                                    gzipOut.write(buf, 0, len);
                                }
                            } finally {
                                try {
                                    gzipOut.close();
                                } catch (Exception ignore) {
                                    ;
                                }
                            }
                        } else {
                            while ((len = br.read(buf)) > 0) {
                                out.write(buf, 0, len);
                            }
                        }
                    } finally {
                        try {
                            out.close();
                        } catch (Exception ignore) {
                            ;
                        }
                    }
                } finally {
                    br.close();
                }
            } catch (Exception e) {
                log.error("Handling file download exception", e);
            }
        } else {
            log.warn("File not found: " + filePath);
        }
    }

    public static void downloadJson(String json,
                                    HttpServletResponse response) {
        downloadString(json, MediaType.APPLICATION_JSON_UTF8_VALUE, "", response);
    }

    public static void downloadJson(String json, String filename,
                                    HttpServletResponse response) {
        downloadString(json, MediaType.APPLICATION_JSON_UTF8_VALUE, filename, response);
    }

    public static void downloadString(String data, String mediaType,
                                      String filename,
                                      HttpServletResponse response) {
        try {
            response.reset(); // 非常重要
            response.setContentType(mediaType);
//            response.setHeader("Access-Control-Allow-Credentials", "true");
//            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Content-Disposition", "attachment; filename=" + filename);
            response.setHeader("Content-Encoding", "gzip");
            OutputStream out = response.getOutputStream();
            try {
                GZIPOutputStream gzipOut = new GZIPOutputStream(out);
                try {
                    gzipOut.write(data.getBytes());
                } finally {
                    try {
                        gzipOut.close();
                    } catch (Exception ignore) {
                        ;
                    }
                }
            } finally {
                try {
                    out.close();
                } catch (Exception ignore) {
                    ;
                }
            }
        } catch (Exception ex) {
            log.warn("下载异常！", ex);
        }
    }

    public static String readTextFile(FileVO fileVO) {
        if (FileExtUtils.existFile(fileVO.getUrl())) {
            String filePath = fileVO.getUrl();

            File file = new File(filePath);
            BufferedReader reader = null;
            StringBuffer sbf = new StringBuffer();
            try {
                reader = new BufferedReader(new FileReader(file));
                String tempStr;
                while ((tempStr = reader.readLine()) != null) {
                    sbf.append(tempStr);
                }
                reader.close();
                return sbf.toString();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                }
            }
            return sbf.toString();
        } else {
            log.warn("File not found: " + fileVO.getUrl());
            return null;
        }
    }

}
